package com.ermao.learnWebmagic.processor;

import com.alibaba.fastjson.JSON;
import com.ermao.learnWebmagic.entity.Video;
import us.codecraft.webmagic.*;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Json;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;

public class VideoPageProcessor implements PageProcessor {
	private final static String SEARCH_PREFIX = "https://api.bilibili.com/x/web-interface/search";
	private final static String SPACE_PREFIX = "https://api.bilibili.com/x/space/arc/search";
	private final static String VIDEO_PREFIX = "http://api.bilibili.com/x/web-interface/view";
	private final static String TAG_PREFIX = "http://api.bilibili.com/x/tag/archive/tags";

	private static final CopyOnWriteArrayList<Video> results = new CopyOnWriteArrayList<>();


	private Site site = Site.me().setRetryTimes(3).setSleepTime(1000).setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36");

	private static AtomicInteger saveCount = new AtomicInteger(0);
	private static AtomicInteger processCount = new AtomicInteger(0);

	@Override
	public void process(Page page) {

		String curUrl = page.getUrl().toString();

		if (curUrl.startsWith(SEARCH_PREFIX)) {
			// 获取UP 主的 mid 的并且拼接出 UP 主主页 URL
			Json json = page.getJson();
			List<String> midList = json.jsonPath("$.data.result[*].mid").all();
			midList = getUnRepeatableMidList(midList);

			for (String mid : midList) {
				Request SpaceReq = new Request();

				SpaceReq.setUrl("https://api.bilibili.com/x/space/arc/search?mid=" + mid + "&pn=1&ps=30&index=1&jsonp=jsonp");

				page.addTargetRequest(SpaceReq);
			}

		} else if (curUrl.startsWith(SPACE_PREFIX)) {
			// 如果是 UP 主主页的 URL，可以提炼出视频标题、作者,
			Json json = page.getJson();
			int size = json.jsonPath("$.data.list.vlist[*]").all().size();

			for (int i = 0; i < (Math.min(size, 30)); i++) {
				processCount.incrementAndGet();

				String bvid = json.jsonPath(("$.data.list.vlist[" + i + "].bvid")).toString();
				String title = json.jsonPath(("$.data.list.vlist[" + i + "].title")).toString();
				String created = json.jsonPath(("$.data.list.vlist[" + i + "].created")).toString();
				String mid = json.jsonPath(("$.data.list.vlist[" + i + "].mid")).toString();

				Video video = new Video();

				video.setVideo_title(title);
				video.setVideo_created(Long.parseLong(created));
				video.setVideo_up_mid(mid);

				Request videoReq = new Request();
				String url = "http://api.bilibili.com/x/web-interface/view?bvid=" + bvid;
				videoReq.setUrl(url);
				videoReq.putExtra("video", video);


				Request tagReq = new Request();
				tagReq.setUrl("http://api.bilibili.com/x/tag/archive/tags?bvid=" + bvid + "&jsonp=jsonp");
				tagReq.putExtra("video", video);

				page.addTargetRequest(videoReq);
				page.addTargetRequest(tagReq);

			}

		} else if (curUrl.startsWith(VIDEO_PREFIX)) {
			Json json = page.getJson();
			Video video = (Video) page.getRequest().getExtra("video");

			video.setVideo_danmaku(Integer.parseInt(json.jsonPath("$.data.stat.danmaku").toString()));
			video.setVideo_play(Integer.parseInt(json.jsonPath("$.data.stat.view").toString()));
			video.setVideo_like(Integer.parseInt(json.jsonPath("$.data.stat.like").toString()));
			video.setVideo_coin(Integer.parseInt(json.jsonPath("$.data.stat.coin").toString()));
			video.setVideo_fav(Integer.parseInt(json.jsonPath("$.data.stat.favorite").toString()));
			video.setVideo_reply(Integer.parseInt(json.jsonPath("$.data.stat.reply").toString()));
			video.setVideo_share(Integer.parseInt(json.jsonPath("$.data.stat.share").toString()));

			if (video.getVideo_title() != null && video.getVideo_tags() != null && video.getVideo_play() != null) {
				results.add(video);
			}


		} else if (curUrl.startsWith(TAG_PREFIX)) {
			Json json = page.getJson();
			Video video = (Video) page.getRequest().getExtra("video");
			List<String> tags = json.jsonPath("$.data.[*].tag_name").all();
			video.setVideo_tags(tags);

			if (video.getVideo_title() != null && video.getVideo_tags() != null && video.getVideo_play() != null) {
				results.add(video);
			}

		}

	}

	@Override
	public Site getSite() {
		return site;
	}

	public static void start(String[] args) {
		Spider spider = Spider
				.create(new VideoPageProcessor())
				.addUrl("https://api.bilibili.com/x/web-interface/search/type?__refresh__=true&_extra=&context=&page=1&page_size=50&order=click&from_source=&from_spmid=333.337&platform=pc&highlight=1&single_column=0&keyword=%E5%92%96%E5%95%A1&category_id=&search_type=video&dynamic_offset=0&preload=true&com2co=true")
				.thread(5);

		spider.run();
		spider.close();
		System.out.println(saveCount.get());
		System.out.println(processCount.get());
		try {

			try (FileChannel fileChannel = new FileOutputStream("data.json", true).getChannel()) {
				for (Video video : results) {
					fileChannel.write(Charset.defaultCharset().encode(JSON.toJSONString(video, false) + ",\n"));
					saveCount.incrementAndGet();
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	// 可以用 Stream 改进
	private List<String> getUnRepeatableMidList(List<String> list) {
		HashSet<String> set = new HashSet<>();
		for (String s : list) {
			if (set.size() >= 20) {
				break;
			}
			set.add(s);
		}

		LinkedList<String> upSpaceURLs = new LinkedList<>(set);
		return upSpaceURLs;
	}

}
